package com.jt.auth.config;


import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 *  当我们在执行登录操作时,底层逻辑(了解):
 *  1)Filter(过滤器)
 *  2)AuthenticationManager (认证管理器)
 *  3)AuthenticationProvider(认证服务处理器)
 *  4)UserDetailsService(负责用户信息的获取及封装)
 */
@Configuration
                                    //重写默认的认证规则
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 此对象负责完成密码的加密
     * BCryptPasswordEncoder此对象提供了一种不可逆的加密方式,相对于md5方式会更加安全
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     * 定义认证管理器对象，这个对象负责完成用户信息的认证，
     * 即判定用户身份信息的合法性，在基于oauth2协议完成认
     * 证时，需要此对象，所以这里讲此对象拿出来交给spring管理
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        //方法返回的对象为后续的oauth2的配置提供服务
        return super.authenticationManagerBean();
    }

    /**
     * 此方法为http请求配置方法，可以在此方法中配置：
     * 配置认证规则
     * 1)那些资源放行(不用登陆即可访问)，假如不做任何配置默认所有资源都匿名访问
     * 2)那些资源必须认证(登陆)才能访问
     * @param http
     * @throws Exception
     */
    //403,没有权限访问
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);//默认跳转登录页面

        //禁用跨域攻击(假如没有禁用,使用postman,httpClients)
        http.csrf().disable();
        //所有必须认证才能访问
//        http.authorizeRequests()
//                .antMatchers("/**")
//                .authenticated();
//        所有资源都放行(在资源服务中去授权)
        http.authorizeRequests().anyRequest().permitAll();
        //限制访问default.html需要认证,其他的都放行
//        http.authorizeRequests()
//                .antMatchers("/default.html")
//                .authenticated()
//                .anyRequest().permitAll();
        //登陆配置(去哪儿里认证，认证成功或失败的处理器是谁)
        //默认get请求
//        http.formLogin().defaultSuccessUrl("/index.html");//redirect index
//        http.formLogin().successForwardUrl("/doIndex");//forward
        //前后端分离的一种做法,是登陆成功要返回json数据
        http.formLogin().successHandler(successHandler())
                .failureHandler(failureHandler());
    }
    /**定义认证失败处理器*/
    @Bean
    public AuthenticationFailureHandler failureHandler() {
//        return new AuthenticationFailureHandler() {
//            @Override
//            public void onAuthenticationFailure(
//                    HttpServletRequest request,
//                    HttpServletResponse response,
//                    AuthenticationException e) throws IOException, ServletException {
//                Map<String,Object> map=new HashMap<>();
//                map.put("status", 500);
//                map.put("message", "login failure");
//                writeJsonToClient(response, map);
//            }
//        };
        return (request,response, e)-> {
                Map<String,Object> map=new HashMap<>();
                map.put("status", 500);
                map.put("message", "login failure");
                writeJsonToClient(response, map);
        };
    }

    /**
     * 定义登录成功处理器
     * @return
     */
    @Bean
    public AuthenticationSuccessHandler successHandler() {
//        return new AuthenticationSuccessHandler() {
//            @Override
//            public void onAuthenticationSuccess(
//                    HttpServletRequest request,
//                    HttpServletResponse response,
//                    Authentication authentication) throws IOException, ServletException {
//                Map<String, Object> map = new HashMap<>();
//                map.put("status", 200);
//                map.put("message", "login success");
//                writeJsonToClient(response,map);
//            }
//
//        };
        return(request,response, authentication) -> {
            //构建map对象封装到要响应到客户端的数据
            Map<String, Object> map = new HashMap<>();
                map.put("status", 200);
                map.put("message", "login success");
                //将map对象转换为json格式字符串并写到客户端
                writeJsonToClient(response,map);
        };
    }
    private void writeJsonToClient(HttpServletResponse response, Map<String, Object> map) throws IOException {
        //设置响应数据的编码方式
        response.setCharacterEncoding("utf-8");
        //设置响应数据的类型
        response.setContentType("application/json;charset=utf-8");
        //将数据响应到客户端
        PrintWriter writer = response.getWriter();
        //将map对象,转换为json
        String jsonStr=new ObjectMapper().writeValueAsString(map);
        writer.println(jsonStr);
        writer.flush();
    }
}
